package m.appserver;

import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.DefaultCookie;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import io.netty.handler.codec.http.multipart.*;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import m.system.RuntimeData;
import m.system.url.UrlMarker;
import m.system.util.*;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class RequestUtil {
	public RequestUtil(ChannelHandlerContext ctx,FullHttpRequest request) {
		this.ctx=ctx;
		this.request=request;
		this.header=request.headers();
		this.uri=this.request.uri();
		String cookie=StringUtil.noSpace(request.headers().get(HttpHeaderNames.COOKIE));
		SystemUtil.println("cookie:",cookie);
		if(!cookie.contains(AuthInfoUtil.SESSION_NAME)) {
			DefaultCookie dc=new DefaultCookie(AuthInfoUtil.SESSION_NAME,GenerateID.generatePrimaryKey());
			dc.setPath("/");
			request.headers().set(HttpHeaderNames.COOKIE,
					ClientCookieEncoder.STRICT.encode(dc)
			);
		}
		addCommonHeader();
		response=new ResponseUtil(ctx,request,this);
	}
	private final String uri;
	private String requestBody;
	private JSONObject requestJson;
	private final ChannelHandlerContext ctx;
	private final FullHttpRequest request;
	private final HttpHeaders header;
	private Map<String,String> paramMap;
	private Map<String,File> fileMap;
	private Set<Cookie> cookies;
	private final ResponseUtil response;

	public ResponseUtil getResponse(){
		return response;
	}

	/**
	 * 获取请求header值
	 *  name  HttpHeaderNames类
	 *
	 */
	public String getHeader(AsciiString name) {
		return this.header.get(name);
	}
	/**
	 * 获取请求header值
	 *  name
	 *
	 */
	public String getHeader(String name) {
		return this.header.get(name);
	}
	/**
	 * 添加公共的header属性 urlmarker.xml配置
	 */
	private void addCommonHeader(){
		Map<String,String> map= UrlMarker.getRequestHeaderMap();
		for(String k : map.keySet()){
			setHeader(k,map.get(k));
		}
	}
	/**
	 * 设置header值
	 *  name  HttpHeaderNames类
	 *  value
	 */
	public void setHeader(AsciiString name,Object value) {
		this.header.set(name, value);
	}
	/**
	 * 设置header值
	 *  name
	 *  value
	 */
	public void setHeader(String name,Object value) {
		this.header.set(name, value);
	}
	public Set<Cookie> getCookies() {
		if(null==this.cookies) {
			cookies=ServerCookieDecoder.STRICT.decode(StringUtil.noSpace(request.headers().get(HttpHeaderNames.COOKIE)));
		}
		return this.cookies;
	}
	public Cookie getCookie(String name) {
		for(Cookie ck : getCookies()) {
			if(ck.name().equals(name)) {
				return ck;
			}
		}
		return null;
	}
	public String getCookieValue(String name) {
		Cookie ck=getCookie(name);
		if(null!=ck) {
			return ck.value();
		}else {
			return "";
		}
	}
	public String getUri() {
		return this.uri;
	}
	public String getIpAddress() {
		String clientIP;
		clientIP = request.headers().get( "X-Forwarded-For" );
		if  (clientIP ==  null ) {
			InetSocketAddress insocket = (InetSocketAddress) ctx.channel()
					.remoteAddress();
			clientIP = insocket.getAddress().getHostAddress();
		}
		return clientIP;
	}
	/**
	 * 获取参数
	 */
	public Map<String, String> getRequestParams() throws IOException {
		if(null==paramMap) {
			paramMap = new HashMap<>();
			// 是GET请求
			QueryStringDecoder getDecoder = new QueryStringDecoder(request.uri());
			getDecoder.parameters().forEach((key, value) -> {
				// entry.getValue()是一个List, 只取第一个元素
				paramMap.put(key, value.get(0));
			});
			// 是POST请求
			if (!StringUtil.noSpace(request.headers().get(HttpHeaderNames.CONTENT_TYPE)).contains("multipart/form-data")
				&&!StringUtil.noSpace(request.headers().get(HttpHeaderNames.CONTENT_TYPE)).contains("application/json")) {
				HttpPostRequestDecoder postDecoder = new HttpPostRequestDecoder(request);
				postDecoder.offer(request);
				List<InterfaceHttpData> parmList = postDecoder.getBodyHttpDatas();
				for (InterfaceHttpData parm : parmList) {
					Attribute data = (Attribute) parm;
					paramMap.put(data.getName(), data.getValue());
				}
			}
		}
		return paramMap;
	}
	/**
	 * 获取requestBody
	 */
	public String getRequestBody() {
		if(null==requestBody){
			ByteBuf jsonBuf = request.content();
			jsonBuf.retain();
			requestBody=jsonBuf.toString(0,jsonBuf.capacity(),CharsetUtil.UTF_8);
			ReferenceCountUtil.release(jsonBuf);
		}
		return requestBody;
	}

	/**
	 * 获取请求的json对象 包含参数
	 */
	public JSONObject getRequestJson() throws IOException {
		if(null==requestJson) {
			String body = getRequestBody();
			if (StringUtil.noSpace(getHeader(HttpHeaderNames.CONTENT_TYPE)).contains("application/json")) {
				requestJson = JSONObject.parseObject(body);
			} else {
				requestJson = new JSONObject();
			}
			Map<String, String> ps = getRequestParams();
			for (String paramName : ps.keySet()) {
				String paramValue = ps.get(paramName);
				ActionUtil.fillJSONObject(requestJson, paramName, paramValue);
			}
		}
		return requestJson;
	}
	/**
	 * 解析文件上传
	 */
	public Map<String,File> getFiles() throws Exception {
		if(null==fileMap) {
			fileMap = new HashMap<>();
			if (StringUtil.noSpace(request.headers().get(HttpHeaderNames.CONTENT_TYPE)).contains("multipart/form-data")) {
				String fPath = RuntimeData.getClassTmp();
				//创建HTTP对象工厂
				HttpDataFactory factory = new DefaultHttpDataFactory(true);
				//使用HTTP POST解码器
				HttpPostRequestDecoder httpDecoder = new HttpPostRequestDecoder(factory, request);
				httpDecoder.setDiscardThreshold(0);
				//获取HTTP请求对象
				//加载对象到加吗器。
				httpDecoder.offer(request);
				//通过迭代器获取HTTP的内容
				List<InterfaceHttpData> InterfaceHttpDataList = httpDecoder.getBodyHttpDatas();
				for (InterfaceHttpData data : InterfaceHttpDataList) {
					//如果数据类型为文件类型，则保存到fileUploads对象中
					if (data != null && InterfaceHttpData.HttpDataType.FileUpload.equals(data.getHttpDataType())) {
						FileUpload fileUpload = (FileUpload) data;
						InputStream in = Files.newInputStream(fileUpload.getFile().toPath());
						String fName = GenerateID.tempKey() + "_uploadFile_" + fileUpload.getFilename();
						FileUtil.writeFile(fPath + fName, in);
						fileMap.put(data.getName(), new File(fPath + fName));
					}
				}
			}
		}
		return fileMap;
	}
	public void deleteUploadFiles() throws IOException {
		if(null!=fileMap) {
			for (String key : fileMap.keySet()) {
				FileUtil.deleteFile(fileMap.get(key).getPath());
			}
		}
	}
}
